<script setup lang="ts">
import { unwrapApiBody, type ApiResponse } from '../../../utils/http/factory'
import { extractFrontMatterDesc } from '../../../utils/markdown-front-matter'
import {
  buildMarkdownExportFileName,
  downloadMarkdownFile,
  normalizeMarkdownImageUrls,
} from '../../../utils/markdown-export'
import { renderSafeMarkdown } from '../../../utils/render-markdown'
import { formatOccurredOnDisplay, occurredOnToIsoAttr } from '../../../utils/timeline-datetime'
import { useAuthSession } from '../../../composables/useAuthSession'

definePageMeta({
  layout: 'public',
})

const route = useRoute()
const publicSlug = computed(() => route.params.publicSlug as string)
const postSlug = computed(() => route.params.postSlug as string)
const { user, loggedIn } = useAuthSession()
const toast = useToast()

type Post = {
  id: number
  title: string
  slug: string
  excerpt: string
  bodyMarkdown: string
  coverUrl: string | null
  publishedAt: Date | null
  visibility: 'private' | 'unlisted' | 'public'
  tags?: string[]
}

const { data, pending, error } = await useAsyncData(
  () => `public-post-${publicSlug.value}-${postSlug.value}`,
  async () => {
    const path = `/api/public/profile/${encodeURIComponent(publicSlug.value)}/posts/${encodeURIComponent(postSlug.value)}`
    const res = await $fetch<ApiResponse<{ post: Post }>>(path)
    return unwrapApiBody(res).post
  },
  { watch: [publicSlug, postSlug] },
)

const renderedBody = computed(() =>
  data.value ? renderSafeMarkdown(data.value.bodyMarkdown) : '',
)

const leadSummary = computed(() => {
  if (!data.value) {
    return ''
  }
  const fm = extractFrontMatterDesc(data.value.bodyMarkdown)
  return (fm || data.value.excerpt || '').trim()
})

const publishedAtLabel = computed(() =>
  data.value?.publishedAt != null ? formatOccurredOnDisplay(data.value.publishedAt) : '',
)

const publishedAtIso = computed(() =>
  data.value?.publishedAt != null ? occurredOnToIsoAttr(data.value.publishedAt) : '',
)

usePageTitle(() => {
  const ps = publicSlug.value
  const t = data.value?.title?.trim()
  if (!t) {
    return ['文章', `@${ps}`]
  }
  return [t, `@${ps}`]
})

/** 当前登录用户是否为该公开主页所有者（可编辑此文） */
const canEditPost = computed(() => {
  const slug = user.value?.publicSlug
  if (!loggedIn.value || !slug) {
    return false
  }
  return slug === publicSlug.value
})

const editPostHref = computed(() =>
  data.value && canEditPost.value ? `/me/posts/${data.value.id}` : '',
)

const canViewComments = computed(() =>
  data.value?.visibility === 'public',
)

function exportMarkdown(): void {
  if (!data.value) {
    return
  }

  try {
    const origin = window.location.origin
    const bodyMarkdown = data.value.bodyMarkdown || ''
    const normalizedMarkdown = normalizeMarkdownImageUrls(bodyMarkdown, origin)
    const filename = buildMarkdownExportFileName({
      slug: data.value.slug,
      id: data.value.id,
    })
    downloadMarkdownFile(filename, normalizedMarkdown)
    toast.add({ title: '已导出 Markdown', color: 'success' })
  } catch {
    toast.add({ title: '导出失败，请稍后重试', color: 'error' })
  }
}
</script>

<template>
  <UContainer class="py-10 space-y-6">
    <div v-if="pending && !data" class="text-muted">
      加载中…
    </div>
    <UAlert v-else-if="error && !data" color="error" title="文章不存在或未公开" />
    <template v-else-if="data">
      <div class="flex flex-wrap items-center gap-2">
        <UButton
          v-if="editPostHref"
          :to="editPostHref"
          color="neutral"
          variant="soft"
          size="sm"
        >
          编辑
        </UButton>
        <UButton
          v-if="data"
          color="neutral"
          variant="soft"
          size="sm"
          :disabled="pending"
          @click="exportMarkdown"
        >
          导出 .md
        </UButton>
      </div>
      <div v-if="data.coverUrl" class="flex justify-center">
        <img
          :src="data.coverUrl"
          alt=""
          class="max-h-64 w-full max-w-2xl rounded-lg object-cover border border-default"
        >
      </div>
      <p v-if="publishedAtLabel" class="text-sm tabular-nums text-muted">
        发布于
        <time :datetime="publishedAtIso" class="text-default">{{ publishedAtLabel }}</time>
      </p>
      <h1 class="text-2xl font-semibold">
        {{ data.title }}
      </h1>
      <PostTagsPostTagBadges v-if="data.tags?.length" :tags="data.tags" class="mt-2" />
      <p v-if="leadSummary" class="text-muted">
        {{ leadSummary }}
      </p>
      <article
        class="prose prose-neutral dark:prose-invert max-w-none prose-a:text-primary prose-img:rounded-lg prose-headings:text-highlighted prose-p:text-default prose-strong:text-highlighted markdown-body green"
        v-html="renderedBody"
      />
      <PostComments v-if="canViewComments" mode="public-post" :public-slug="publicSlug" :post-slug="postSlug" />
    </template>
  </UContainer>
</template>
